package com.android.takegism.service;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ContentValues;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;

import androidx.annotation.Nullable;

import com.android.takegism.R;
import com.android.takegism.dao.SensorPackageDao;
import com.android.takegism.ui.AdminActivity;
import com.android.takegism.utils.Clue;
import com.android.takegism.utils.ClueUtils;
import com.android.takegism.utils.CommandUtils;
import com.android.takegism.utils.MyContext;
import com.android.takegism.utils.SensorPackage;
import com.android.takegism.utils.SensorUiItem;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

public class AdminService extends Service {

    private Thread communicationThread;
    private ReentrantLock lock = new ReentrantLock();
    private String channelId = "com.android.takagism.service.AdminService";

    private transient Boolean taskRunning = true;
    private Notification.Builder builder;
    private NotificationManager manager;

    private byte[] msgBuffer = null;


    private class SendCommandsTask implements Runnable {
        @Override
        public void run() {
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while (taskRunning) {
                if (ifCanSend()) {
                    sendCommand();
                }
                try {
                    Thread.sleep(2 * 60 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    continue;
                }

            }
        }
    }

    private ClueUtils clueUtils = ClueUtils.getInstance();
    private int plotCnt = 0;
    private int clueCnt = 0;
    private CommandUtils commandUtils = CommandUtils.getInstance();
    private HashMap<String, String> encodeCommandsMap;

    private void sendCommand() {

        // 第一次发剧情#Plot+i#
        if (plotCnt == 0) {
            sendMessage(encodeCommandsMap.get("剧情0"));
            plotCnt++;
            return;
        }
        // 发三次线索
        if (clueCnt < 3) {
            String s = encodeCommandsMap.get("线索" + clueCnt);
            sendMessage(s);
            System.out.println();
            clueCnt++;
            return;
        }
        if (clueCnt == 3) {
            // 第二次发剧情
            if (plotCnt == 1) {
                sendMessage(encodeCommandsMap.get("剧情1"));
                plotCnt++;
            } else {
                sendMessage(encodeCommandsMap.get("线索" + clueCnt));
                clueCnt++;
                // clueCnt = 4;
            }
            return;
        }
        // 发2次线索
        if (clueCnt < 6) {
            sendMessage(encodeCommandsMap.get("线索" + clueCnt));
            clueCnt++;
            return;
        }
        // 发1次线索
        if (clueCnt == 6) {
            if (plotCnt == 2) {
                sendMessage(encodeCommandsMap.get("剧情2"));
                plotCnt++;
            } else {
                sendMessage(encodeCommandsMap.get("线索" + clueCnt));
                clueCnt++;
//                7
            }
            return;
        }
        if (clueCnt == 7) {
            sendMessage(encodeCommandsMap.get("线索" + clueCnt));
            clueCnt++;
            return;
        }
        if (plotCnt == 3) {
            sendMessage(encodeCommandsMap.get("剧情3"));
            plotCnt++;
            return;
        }
    }

    private class CommunicationTask implements Runnable {
        @Override
        public void run() {
            while (taskRunning) {
                try {
                    while (isEmpty()) {
                        synchronized (taskRunning) {
                            taskRunning.wait(1000);
                        }
                    }
                    SensorPackage curPackage = getSensorPackage();

                    for (Socket socket : sockets) {
                        if (!socket.isConnected() || !socket.getKeepAlive() || socket.isClosed()) {
                            sockets.remove(socket);
                            if (!socket.isClosed()) {
                                socket.close();
                            }
                        }
                        OutputStream outputStream = socket.getOutputStream();
                        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
                        objectOutputStream.writeObject(curPackage);
                        objectOutputStream.flush();
                        objectOutputStream.close();
                    }
                } catch (IOException | InterruptedException e) {
                    e.printStackTrace();
                    continue;
                }

            }
        }
    }

    /**
     * 接收连接请求，同时为每个连接增加一条读线程
     */
    private class AcceptSocketTask implements Runnable {
        @Override
        public void run() {
            while (taskRunning) {
                try {
                    Socket accept = serverSocket.accept();
                    sockets.add(accept);
                    InputStream in = accept.getInputStream();
                    OutputStream out = accept.getOutputStream();
                    br = new BufferedReader(new InputStreamReader(accept.getInputStream()));
                    bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
//                    System.out.println("暂时不发送数据确定能通信...");


                    //为每个连接再增加读写线程
                    int id = sockets.size();
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
//                            方式一END
//                            while (accept.isConnected() && !accept.isClosed()) {
//                                byte[] buff = new byte[1024*2];
//                                int readSize = -1;
//                                try {
//                                    if ((readSize = in.read(buff)) != -1) {
//                                        String str = new String(buff, 0, readSize, "UTF-8");                  //编码方式  解决收到数据乱码
//
//                                        Message msg = new Message();
//                                        msg.what =0x6002;
//                                        msg.obj = str;
//                                        AdminActivity.mainHandler.sendMessage(msg);
//
//                                        System.out.println("接收来自第" + id + "个socket" + accept + "的数据：" + str);
//                                        System.out.println("=======(未指明handler有谁处理！)发送handler指明信息/类型（有对应处理方法：打印输出、逻辑运算控制？）=======");
//
//                                        out.write("YES接收到了数据".getBytes("UTF-8"));
//                                        System.out.println("向第" + id + "个socket" + accept + "发送了数据=======>");
//                                    }
//                                } catch (IOException e) {
//                                    e.printStackTrace();
//                                }
//                            }
//                          方法一END

                            try {
                                String str;
                                while (accept.isConnected() && !accept.isClosed() && (str = br.readLine()) != null) {

                                    System.out.println("接收来自第" + id + "个socket" + accept + "的数据：" + str);
                                    System.out.println("=======(未指明handler有谁处理！)发送handler指明信息/类型（有对应处理方法：打印输出、逻辑运算控制？）=======");
                                    Message msg = AdminActivity.mainHandler.obtainMessage();
                                    msg.what = 0x6002;
                                    msg.obj = str;
                                    AdminActivity.mainHandler.sendMessage(msg);

                                    if (!str.contains("#")) {
                                        bw.write("SERVER接收到了数据");
                                        bw.newLine();
                                        bw.flush();
                                        System.out.println("向第" + id + "个socket" + accept + "发送了数据=======>");
                                    }
                                }
                            } catch (IOException e) {
                                e.printStackTrace();
                                try {
                                    br.close();
                                } catch (IOException ioException) {
                                    ioException.printStackTrace();
                                }
                            }
                            try {
                                if (in == null)
                                    return;
                                in.close();
                                if (accept.isConnected())
                                    accept.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }).start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private BufferedReader br = null;
    private BufferedWriter bw = null;

    /**
     * 向客户端广播发送数据
     */
    public void sendMessage(final String msg) {
        if (sockets.isEmpty()) {
            System.out.println("尚未有客户端连接");
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (Socket socket : sockets) {
                    System.out.println("列表中socket:" + socket);
//                    if (!socket.isConnected() || socket.isClosed())
                    if (!socket.isConnected() || socket.isClosed()) {
                        System.out.println("关闭连接");
                        sockets.remove(socket);
                        if (!socket.isClosed()) {
                            try {
                                socket.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                    System.out.println("isClosed?:" + socket.isClosed() + "\tisConnected?:" + socket.isConnected());
                    try {
                        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                        bw.write(msg);
                        bw.newLine();
                        bw.flush();
//                        方式一
//                        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//                        msgBuffer = msg.getBytes("UTF-8");
//                        OutputStream outputStream = socket.getOutputStream();
//                        outputStream.write(msgBuffer);
//                        outputStream.write('\n');
//                        outputStream.flush();
//                        方式一END
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    System.out.println("向socket" + socket + "发送消息:" + msg);
                }
            }
        }).start();
    }

    LinkedList<Socket> sockets = new LinkedList<>();

    private LinkedList<SensorPackage> sensorPackagesPool = new LinkedList<>();
    private ConcurrentHashMap<String, SensorPackage> lastSensorPackage = new ConcurrentHashMap<>();

    synchronized public void putSensorPackage(SensorPackage sensorPackage) {
        sensorPackagesPool.add(sensorPackage);
        synchronized (taskRunning) {
            taskRunning.notify();
        }
    }

    synchronized public SensorPackage getSensorPackage() {
        return sensorPackagesPool.pop();
    }

    synchronized boolean isEmpty() {
        return sensorPackagesPool.isEmpty();
    }


    private NotificationChannel channel;
    private ServerSocket serverSocket;

    @Override
    public void onCreate() {
        channel = new NotificationChannel(channelId, "Channel admin", NotificationManager.IMPORTANCE_DEFAULT);
        try {
            serverSocket = new ServerSocket(8888);
            new Thread(new AcceptSocketTask()).start();
            AdminActivity.mainHandler.sendEmptyMessage(0x6000);
//            new Thread(new CommunicationTask()).start();
//            new Thread(new NoPersonTask()).start();
            new Thread(new SendCommandsTask()).start();
        } catch (IOException e) {
            AdminActivity.mainHandler.sendEmptyMessage(0x6001);
            e.printStackTrace();
        }
        System.out.println("服务启动成功！");

        NotificationChannel channel = new NotificationChannel(channelId, "Channel 2", NotificationManager.IMPORTANCE_DEFAULT);
        manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.createNotificationChannel(channel);
        builder = new Notification.Builder(this, channel.getId());


        HashMap<String, Object> stringStringHashMap = new HashMap<>();
        stringStringHashMap.put("string", "未检测到声音222");
        defaultSensorPackage.setData(stringStringHashMap);

        MyContext.getInstance().setStatics("adminService", this);
        encodeCommandsMap = commandUtils.getEncodeCommandsMap();
        super.onCreate();
    }

    //    Context testContext = AdminActivity;
    // 检测到声音
    private void sendTicker() {

        Intent intent = new Intent(this, AdminActivity.class);
        builder
                .setContentIntent(PendingIntent.getActivity(this, 0, intent, 0))
                .setAutoCancel(true)
                .setTicker("提醒")
                .setContentText("检测到声音...注意！")
                .setContentTitle("声音")
                .setSmallIcon(R.mipmap.ic_launcher_round)
                .setWhen(System.currentTimeMillis())
        ;

        manager.notify((int) System.currentTimeMillis(), builder.build());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String type = intent.getStringExtra("type");
        if (type != null) {
            Clue clue;
            System.out.println("查看clue" + intent.getSerializableExtra("clue"));
            if (intent.getSerializableExtra("clue") == null)
                clue = new Clue(0, "空线索");
            else
                clue = (Clue) intent.getSerializableExtra("clue");
            //先编码称String
            // TODO
            String msg = CommandUtils.encodePuzzleCommand(clue);
            sendCommand();
        } else {
            //        }==========================================下面的暂时用不到
            SensorPackage sensorPackage = (SensorPackage) intent.getExtras().get("sensorPackage");
            putSensorPackage(sensorPackage);
            lastSensorPackage.put(sensorPackage.getDataType(), sensorPackage);
            UiExecute(sensorPackage);
            SensorPackageDao.insert(sensorPackage);
            ExceptionExecute(sensorPackage);
        }
        return super.onStartCommand(intent, flags, startId);
    }

    private SensorPackage defaultSensorPackage = new SensorPackage("声音传感器");

    private int UiExecute(SensorPackage sensorPackage) {
        String dataType = sensorPackage.getDataType();
        String dataString = sensorPackage.getDataString();
        Message message = new Message();
        int id = SensorUiItem.getString2ImageIdMap().get(dataType);
        SensorUiItem sensorUiItem = new SensorUiItem(id, dataType, dataString);
        message.obj = sensorUiItem;

        Handler messageHandler = AdminActivity.messageHandler;
//        Handler messageHandler = (Handler) MyContext.getInstance().getStatics("messageHandler");
        System.out.println("准备进来");
        if (messageHandler == null) {

            Intent intent = new Intent(getApplicationContext(), AdminActivity.class);
//            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        } else {
            System.out.println("发送HANDLER");
            messageHandler.sendMessage(message);
        }
        return 0;
    }

    private void sendMsgTicker(final String title, final String msg) {

        Intent intent = new Intent(this, AdminActivity.class);
        builder
                .setContentIntent(PendingIntent.getActivity(this, 0, intent, 0))
                .setAutoCancel(true)
                .setTicker("提醒")
                .setContentText(msg)
                .setContentTitle(title)
                .setSmallIcon(R.mipmap.ic_launcher_round)
                .setWhen(System.currentTimeMillis())
        ;

        manager.notify((int) System.currentTimeMillis(), builder.build());
    }


//    private ContentValues contentValues;

    private int ExceptionExecute(SensorPackage sensorPackage) {

        System.out.println("启动了");
        SensorPackage cgq = sensorPackage;
        Object dataString = cgq.getDataString();

        switch (cgq.getDataType()) {
            case "声音传感器":
                if (dataString.equals("检测到声音")) {
                    sendTicker();
                    hasVoice = true;
                } else {
                    hasVoice = false;
                }
                break;
            case "无效传感器":
                sendMsgTicker("连接异常", dataString.toString());
                break;
            case "红外测距传感器":
                红外测距传感器大于x(cgq);
                break;
            case "光照传感器":
                光照传感器大于x(cgq);
                break;
            case "振动传感器":
                check振动传感器(cgq);
                break;

            case "光敏电阻传感器":
            case "光敏二极管传感器":
                bak();
                break;

            case "人体红外传感器":
                saveState(cgq);
                break;


            case "LM35DZ 线性模拟温度传感器":
            case "温湿度传感器(低精度)":
            case "温湿度传感器":
                executeTemperatureAndHumidity(cgq);
                break;

            case "灯控制器":
                openLight();
                break;

        }
        return 0;
    }

    private boolean hasPerson = false;
    private boolean hasVoice = false;
    private boolean isVibrating = false;
    private boolean greaterThan_threshold_illumination = false;
    private boolean greaterThan_threshold_distance = false;

    private boolean ifCanSend() {
        // TODO
        if (hasPerson && hasVoice && isVibrating){
            return true;
        }
        if (!isVibrating && greaterThan_threshold_distance){
            return true;
        }
        if (isVibrating && greaterThan_threshold_illumination){
            return true;
        }
        if (greaterThan_threshold_illumination && !greaterThan_threshold_distance){
            return true;
        }
        if (!hasVoice && !greaterThan_threshold_distance){
            return true;
        }
        return true;
    }

    private void saveState(SensorPackage cgq) {
        // 保存信息
        if (cgq.getDataString().equals("有人")) {
            hasPerson = true;
        } else {
            hasPerson = false;
        }
    }

    private void bak() {
        System.out.println("保留方法");
    }

    private void check振动传感器(SensorPackage cgq) {
        // 组合指令
        String dataString = cgq.getDataString();
        String 检测到振动 = "检测到振动";
        if (dataString.equals(检测到振动)) {
            isVibrating = true;
        } else {
            isVibrating = false;
        }
    }

    private void 光照传感器大于x(SensorPackage cgq) {
        // 关灯指令
        HashMap<String, Object> data = cgq.getData();
        int guang_zhao = (int) data.get("光强");
        ContentValues cv = SensorPackageDao.queryManage();
        if (cv == null) {
            sendMsgTicker("错误", "请先升级版本，建立数据库");
        } else {
            Integer threshold_illumination = cv.getAsInteger("threshold_illumination");
            if (guang_zhao > threshold_illumination) {
                greaterThan_threshold_illumination = true;
            } else {
                greaterThan_threshold_illumination = false;
            }
        }
    }

    private void 红外测距传感器大于x(SensorPackage cgq) {
        HashMap<String, Object> data = cgq.getData();
        float ju_li = (float) data.get("距离");
        ContentValues cv = SensorPackageDao.queryManage();
        if (cv == null) {
            sendMsgTicker("错误", "请先升级版本，建立数据库");
        } else {
            Integer threshold_distance = cv.getAsInteger("threshold_distance");
            if (ju_li > threshold_distance) {
                greaterThan_threshold_distance = true;
            } else {
                greaterThan_threshold_distance = false;
            }
        }
    }

    private void openLight() {
        ContentValues cv = SensorPackageDao.queryManage();
        if (cv == null) {
            cv = new ContentValues();
            cv.put("deng", 1);
            SensorPackageDao.insertManage(cv);
        } else {
            cv.put("deng", 1);
            SensorPackageDao.updateManage(cv);
        }
    }

    private void executeTemperatureAndHumidity(SensorPackage cgq) {
        HashMap<String, Object> data = cgq.getData();
        // TODO
        float Temperature = (float) data.getOrDefault("温度", 0.0f);
        float Humidity = (float) data.getOrDefault("湿度", 0.0f);
        String str = cgq.getDataString();
        ContentValues cv = SensorPackageDao.queryManage();
        if (cv == null) {
            cv = new ContentValues();
            cv.put("wen_shi_du", str);
            SensorPackageDao.insertManage(cv);
        } else {
            cv.put("wen_shi_du", str);
            SensorPackageDao.updateManage(cv);
        }
    }

    @Override
    public void onDestroy() {
        System.out.println("服务已经停止");
        taskRunning = false;
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
